package com.gzj.environment.framework.redis;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashSet;
import java.util.Set;

@Configuration
@ConditionalOnExpression("'${spring.redis.mode}'.equals('sentinel')")
public class RedisSentinelConfig {

    @Value("${spring.redis.sentinel.master}")
    private String masterName;

    @Value("${spring.redis.sentinel.nodes}")
    private String nodes;

    @Value("${spring.redis.maxTotal}")
    private Integer maxTotal;

    @Value("${spring.redis.maxIdle}")
    private Integer maxIdle;

    @Value("${spring.redis.minIdle}")
    private Integer minIdle;

    @Value("${spring.redis.password}")
    private String password;

    /**
     * @desc 初始化连接池配置对象
     * @author tsing
     * @date 20190520 16:00
     * @return redis.clients.jedis.JedisPoolConfig
     */
    @Bean(name = "jedisPoolConfig")
    public JedisPoolConfig getJedisPoolConfig() {
        JedisPoolConfig config = new JedisPoolConfig();
        // 最大总量
        config.setMaxTotal(maxTotal);
        // 设置最大空闲数量
        config.setMaxIdle(maxIdle);
        // 设置最小空闲数量
        config.setMinIdle(minIdle);
        // 常规配置
        config.setTestOnBorrow(true);
        config.setTestOnReturn(true);
        return config;
    }

    /**
     * @desc 哨兵模式配置【配置RedisSentinelConfiguration】
     * @return
     */
    @Bean(name = "redisSentinelConfiguration")
    public RedisSentinelConfiguration getRedisSentinelConfiguration(){
        RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
        // 配置redis的sentinel
        Set<RedisNode> redisNodeSet = new HashSet<>();
        String [] subNodes = nodes.split(",");
        if(subNodes!=null && subNodes.length>0){
            int len = subNodes.length;
            for(int i=0;i<len;i++){
                String [] subSentinel = subNodes[i].split(":");
                RedisNode redisNode = new RedisNode(subSentinel[0],Integer.parseInt(subSentinel[1]));
                redisNodeSet.add(redisNode);
            }
        }
        redisSentinelConfiguration.setSentinels(redisNodeSet);
        redisSentinelConfiguration.setMaster(masterName);
        return redisSentinelConfiguration;

    }

    /**
     * @desc 创建redis连接工厂
     * @param jedisPoolConfig
     * @param redisSentinelConfiguration
     * @return
     */

    @Bean(name = "jedisConnectionFactory")
    public JedisConnectionFactory getJedisConnectionFactory(@Qualifier("jedisPoolConfig")JedisPoolConfig jedisPoolConfig,
                                                            @Qualifier("redisSentinelConfiguration")RedisSentinelConfiguration redisSentinelConfiguration){
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(redisSentinelConfiguration, jedisPoolConfig);
        if (StrUtil.isNotBlank(password)) {
            jedisConnectionFactory.setPassword(password);
        }

        return jedisConnectionFactory;
    }



//    /**
//     * @desc 实例化redisTemplate
//     * @param jedisConnectionFactory
//     * @return
//     */
//    @Bean(name = "redisTemplate")
//    public RedisTemplate<String,Object> getRedisTemplate(@Qualifier("jedisConnectionFactory")JedisConnectionFactory jedisConnectionFactory){
//        RedisTemplate redisTemplate = new RedisTemplate();
//        redisTemplate.setConnectionFactory(jedisConnectionFactory);
//        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//        ObjectMapper objectMapper = new ObjectMapper();
//        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
//        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//        // key采用String的序列化方式
//        redisTemplate.setKeySerializer(stringRedisSerializer);
//        // hash的key也采用String的序列化方式
//        redisTemplate.setHashKeySerializer(stringRedisSerializer);
//        // value采用jackson序列化方式
//        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//        // hash的value采用jackson序列化方式
//        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
//        redisTemplate.afterPropertiesSet();
//        return redisTemplate;
//    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(@Qualifier("jedisConnectionFactory")JedisConnectionFactory jedisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate(jedisConnectionFactory);
        //定义key序列化方式
        //RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long类型会出现异常信息;需要我们上面的自定义key生成策略，一般没必要
        //定义value的序列化方式
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // template.setKeySerializer(redisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}
